package cc.fs.zhihuapp.utils.myutils;

import android.util.Log;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpUriRequest;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.SocketException;

import cc.fs.zhihuapp.utils.CacheFileInfoDao;
import cc.fs.zhihuapp.utils.Constants;
import cc.fs.zhihuapp.utils.HttpUtils;
import cc.fs.zhihuapp.utils.MediaPlayerProxy;
import cc.fs.zhihuapp.utils.ProxyFileUtils;

/**
 * Created by fostion on 2015/11/3.
 */
public class MyRequestDealThread extends Thread {

    private String TAG = "--MyRequestDealThread--";

    ProxyFileUtils fileUtils;
    /**
     * MediaPlayer发出的原始请求Range Start
     */
    private int originRangeStart;
    /**
     * 和本地缓存判断后，需要发出的请求Range Start
     */
    private long realRangeStart;
    /**
     * 使用数据库记录数据
     */
    private CacheFileInfoDao cacheDao;

    private Socket client;
    private HttpUriRequest request;

    private void d(String msg) {
        Log.d(TAG, msg);
    }

    public MyRequestDealThread(HttpUriRequest _request,Socket _client) {
        client = _client;
        request = _request;
        cacheDao = CacheFileInfoDao.getInstance();
    }

    @Override
    public void run() {
        try {
            //获得需要下载的播放一个片段
            fileUtils = ProxyFileUtils.getInstance(request.getURI(), true);
            d("需要下载片段cache名称： " + fileUtils.getFileName() + " 文件大小： " + fileUtils.getLength());
            processRequest(request, client);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private int getRangeStart(HttpUriRequest request) {
        Header rangeHeader = request.getFirstHeader(Constants.RANGE);
        if (rangeHeader != null) {
            String value = rangeHeader.getValue();
            return Integer.valueOf(value.substring(value.indexOf("bytes=") + 6, value.indexOf("-")));
        }
        return 0;
    }

    /**
     * 伪造：Response Header ,返回cache给播放器
     *
     * @param rangeStart 数据开始
     * @param rangeEnd   数据结束
     * @param fileLength 文件长度
     * @param audioCache 二进制流
     */
    private void sendLocalHeaderAndCache(int rangeStart, int rangeEnd, int fileLength, byte[] audioCache) throws IOException {

        //返回MediaPlayer Header信息
        String httpString = HttpUtils.genResponseHeader(rangeStart, rangeEnd, fileLength);
        byte[] httpHeader = httpString.toString().getBytes();
        //先将头部信息通过socket 返回返回
        client.getOutputStream().write(httpHeader, 0, httpHeader.length);
        if (audioCache != null && audioCache.length > 0) {//若是有数据流，同时也将数据流传进去
            client.getOutputStream().write(audioCache, 0, audioCache.length);
        }

    }

    /**
     * 处理播放器的具体请求
     */
    private void processRequest(HttpUriRequest request, Socket client) throws IOException {
        if (request == null) {
            d("player request 请求数据为空，不处理，结束进程");
            return;
        }

        try {
            /*******************************************************************************************
             * 具体的数据比较操作
             */
            byte[] audioCache = null;
            //获得播放器请求的数据开始
            originRangeStart = getRangeStart(request);
            d("原始请求Range起始值：" + originRangeStart + " 本地缓存长度：" + fileUtils.getLength());
            //通过查找数据库需要获取文件片段缓存文件大小
            int cacheFileSize = cacheDao.getFileSize(fileUtils.getFileName());
        /*
         * 本地有缓存，先将缓存部分返回去，无需远程发送请求，将本地缓存返回给播放器
         * fileUtils.getLength 是已缓存文件大小，cacheFileSize是应该要缓存文件大小
         */
            d("文件应该缓存大小是: " + cacheFileSize + "  文件大小实际大小是： " + fileUtils.getLength());
            if (fileUtils.isEnable() && fileUtils.getLength() == cacheFileSize) {
                d("请求数据本地有缓存，直接从本地缓存传回去");
                audioCache = fileUtils.read(originRangeStart, Constants.AUDIO_BUFFER_MAX_LENGTH);
                sendLocalHeaderAndCache(originRangeStart, cacheFileSize - 1, cacheFileSize, audioCache);
                return;
            }
            //todo 这里需要网络判断
        /*
         * 请求Range起始值和本地缓存比对。如果有缓存，得到缓存内容，修改Range。 如果没有缓存，则Range不变。
         */
            if (fileUtils.isEnable() && originRangeStart < fileUtils.getLength()) {
                //请求数据已全部缓存,读取到文件最大缓存数，若是还是缺少，mediaplayer将会在发请求
                audioCache = fileUtils.read(originRangeStart, Constants.AUDIO_BUFFER_MAX_LENGTH);
                d("此处数据已经缓存了:" + audioCache.length);
                // 得到需要发送请求Range Start（本地缓存结尾位置+1=缓存长度）
                realRangeStart = fileUtils.getLength();
                // 替换请求Header
                request.removeHeaders(Constants.RANGE);
                request.addHeader(Constants.RANGE, Constants.RANGE_PARAMS + realRangeStart + "-");
            } else {
                realRangeStart = originRangeStart;
            }

            // 缓存是否已经到最大值（如果缓存已经到最大值，则只需要返回缓存）
            boolean isCacheEnough = (audioCache != null && audioCache.length == Constants.AUDIO_BUFFER_MAX_LENGTH) ? true : false;

            /*
             * 如果缓存足够，且本地有文件长度，则直接发送缓存,不发送请求。。。。。。。。。。。。。。。。。。。
			 * 如果缓存足够，本地没有文件长度，则发送请求，使用ResponseHeader，返回缓存,!不接收ResponseContent
			 * 如果缓存不足，则发送请求，使用ResponseHeader，返回缓存，!返回Response Content
			 */
            // 缓存足够&&有文件大小
            if (isCacheEnough && cacheFileSize > 0) {
                sendLocalHeaderAndCache(originRangeStart, cacheFileSize - 1, cacheFileSize, audioCache);
            } else {
                //缓存量不足，或者数据库没有文件大小
                HttpResponse realResponse = null;
                /*
				 * 返回Header和Cache
				 */

                // 如果数据库没有存文件大小，则获取（处理数据库没有文件大小的情况）
                if (cacheFileSize <= 0) {
                    d("数据库未包含文件大小，发送请求");
                    realResponse = HttpUtils.send(request);
                    if (realResponse == null) {
                        return;
                    }
                    //将数据包的大小保存到数据库，以便下次使用
                    cacheFileSize = getContentLength(realResponse);
                }
                //先将头写进去，然后写数据
                sendLocalHeaderAndCache(originRangeStart, cacheFileSize - 1, cacheFileSize, audioCache);// ?这里有一个问题，为什么要返回应答服务器

                //缓存不足，需要请求获取
                if (realResponse == null) {
                    d("缓存不足，发送请求");
                    realResponse = HttpUtils.send(request);
                    if (realResponse == null) {
                        return;
                    }
                }

                //无论是之前没有请求还是缓存不足，都可以直接发送了请求，现在可以直接使用realResponse缓存起来了
                d("接收ResponseContent"); //并缓存在本地
                InputStream data = realResponse.getEntity().getContent();
                if (!isCacheEnough) {
                    byte[] buff = new byte[1024 * 40];
                    boolean isPrint = true;
                    int fileLength = 0;
                    int readBytes;
                    while (Thread.currentThread() == MyMediaPlayerProxy.downloadThread
                            && (readBytes = data.read(buff, 0, buff.length)) != -1) {
                        long fileBufferLocation = fileLength + realRangeStart;//文件未下载前大小
                        fileLength += readBytes;
                        long fileBufferEndLocation = fileLength + realRangeStart;//文件下载后大小
                        // 保存文件
                        if (fileUtils.getLength() == fileBufferLocation) {//文件大小（开始）== 文件需要下载的开始
                            fileUtils.write(buff, readBytes);
                        }
                        // 打印缓存大小
                        if (System.currentTimeMillis() / 1000 % 2 == 0) {
                            if (isPrint) {
                                d("Cache Size:" + readBytes + " File Start:" + fileBufferLocation
                                        + "  File End:" + fileBufferEndLocation);
                                isPrint = false;
                            }
                        } else {
                            isPrint = true;
                        }
                        //返回给服务器
                        client.getOutputStream().write(buff, 0, readBytes);
                    }
                }
            }
        } catch (SocketException e) {
            d("连接被终止");
        } catch (Exception e) {
            d("连接失败");
        } finally {
            client.close();
            d("代理关闭");
        }
    }


    /**
     * 计算response长度
     */
    private int getContentLength(HttpResponse response) {
        int contentLength = 0;
        Header header = response.getFirstHeader(Constants.CONTENT_RANGE);
        if (header != null) {
            String range = header.getValue();
            contentLength = Integer.valueOf(range.substring(range.indexOf("-") + 1, range.indexOf("/"))) + 1;
        } else {
            header = response.getFirstHeader(Constants.CONTENT_LENGTH);
            if (header != null) {
                contentLength = Integer.valueOf(header.getValue());
            }
        }
        if (contentLength != 0) {
            d("数据库缺少文件记录为: "+fileUtils.getFileName() +"  文件大小为:"+contentLength);
            cacheDao.insertOrUpdate(fileUtils.getFileName(), contentLength);
        }
        return contentLength;
    }
}
